package com.stox.ui.javafx.core.util;

import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;

import com.stox.design.Callback;

public abstract class TreeUtil {

	public static <T> T search(TreeView<T> treeView, Callback<T, Boolean> matcher, int start, boolean forward) {
		TreeItem<T> root = treeView.getRoot();
		TreeItem<T> startItem = start < 0 ? treeView.getRoot() :
			start > 0 ? getLastLeaf(root) : treeView.getSelectionModel().getSelectedItem();
		if(null == startItem) startItem = treeView.getRoot();
		TreeItem<T> treeItem = forward ? nextTreeItem(startItem) : previousTreeItem(startItem);
		do {
			if(null == treeItem) break;
			if(null == treeItem.getValue()) continue;
			if(matcher.execute(treeItem.getValue())){
				select(treeView, treeItem);
				return treeItem.getValue();
			}
			treeItem = forward ? nextTreeItem(treeItem) : previousTreeItem(treeItem);
		}while(treeItem != null);
		return null;
	}
	
	public static <T> TreeItem<T> nextTreeItem(TreeItem<T> treeItem) {
		if (treeItem.getChildren().isEmpty()) {
			TreeItem<T> nextSibling = treeItem.nextSibling();
			TreeItem<T> parent = treeItem.getParent();
			if (nextSibling == null) {
				do {
					if (parent == null)
						return null;
					nextSibling = parent.nextSibling();
					if (nextSibling != null)
						return nextSibling;
					parent = parent.getParent();
				} while (true);
			} else
				return nextSibling;
		} else
			return treeItem.getChildren().get(0);
	}

	public static <T> TreeItem<T> previousTreeItem(TreeItem<T> treeItem) {
		TreeItem<T> parent = treeItem.getParent();
		if (parent == null)
			return null;
		TreeItem<T> previousSibling = treeItem.previousSibling();
		if (previousSibling != null) {
			if (previousSibling.getChildren().size() == 0) {
				return previousSibling;
			} else {
				return getLastLeaf(previousSibling);
			}
		} else
			return parent;
	}

	public static <T> TreeItem<T> getLastLeaf(TreeItem<T> treeItem) {
		while (!treeItem.isLeaf())
			treeItem = getLastChild(treeItem);
		return treeItem;
	}

	public static <T> TreeItem<T> getLastChild(TreeItem<T> treeItem) {
		if (treeItem.getChildren().size() == 0)
			return null;
		else
			return treeItem.getChildren()
					.get(treeItem.getChildren().size() - 1);
	}

	public static <T> void expand(TreeItem<T> treeItem) {
		if (null != treeItem.getParent())
			expand(treeItem.getParent());
		if (!treeItem.isLeaf())
			treeItem.setExpanded(true);
	}
	
	public static <T> T getNextValue(TreeView<T> treeView, boolean forward){
		TreeItem<T> treeItem = treeView.getSelectionModel().getSelectedItem();
		if(null == treeItem) return null;
		treeItem = forward ? TreeUtil.nextTreeItem(treeItem) : TreeUtil.previousTreeItem(treeItem);
		if(null == treeItem) return null;
		select(treeView, treeItem);
		return treeItem.getValue();
	}
	
	public  static <T> void select(TreeView<T> treeView, TreeItem<T> treeItem){
		int row = treeView.getRow(treeItem);
		if(row < 0) return;
		TreeUtil.expand(treeItem);
		treeView.scrollTo(row);
		treeView.getSelectionModel().clearAndSelect(row);
	}
	
}
